/*
 * Renderizador.java
 *
 * Created on 16 de Janeiro de 2008, 14:20
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package br.com.cpqd.ssar.posprocessamento;

import com.sun.opengl.util.GLUT;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.text.FieldPosition;
import java.text.Format;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.Formatter;
import java.util.Vector;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;

/**
 *
 * @author igorj
 */
public class Renderizador implements GLEventListener, KeyListener, MouseListener, MouseMotionListener, MouseWheelListener {

    private float[] luzAmbiente = {0.8f, 0.5f, 0.5f, 0.6f};
    private float[] luzDifusa = {0.8f, 0.8f, 0.8f, 0.8f};           // "cor"
    private float[] luzEspecular = {0.5f, 0.5f, 0.5f, 0.5f};     // "brilho"
    private float[] posicaoLuz = {100.0f, 100.0f, 100.0f, 0.0f};    // (x,y,z,w)
    private float[] mat_shineness = {50.0f};
    // Capacidade de brilho do material
    private float[] especularidade = {1.0f, 1.0f, 1.0f, 1.0f};
    private int especMaterial = 30;
    private int[] viewport = new int[4];
    private static GL gl;
    private static final GLU glu = new GLU();
    private static final GLUT glut = new GLUT();
    private GLCanvas glCanvas;
    private CubeElement c = new CubeElement();
    private CubeElement[] list;
    char t;
    private Vector vAmp,  vTempo;
    private float xMax,  yMin = 0,  yMax = 0;
    private float qtdGradeX = 5;
    private float qtdGradeY = 8;         //quantidade de grade que pode ser definido em formulario
    // Databuffer that holds the loaded image.
    private byte[] imgRGBA = null; // This is for the old JOGL version.
    private ByteBuffer imgRGBABuf; // For JOGL version higher 1.1.
//    // Image size retrieved durung loading,
//    // re-used when image is drawn.
//    int imgHeight;
//    int imgWidth;
//
//    // To copy the content of the current frame.
//    int frameWidth = 800;
//    int frameHeight = 600;
    private boolean statusSave = false;
    private boolean statusGrid = true;
    public boolean statusPrint = true;
    private boolean statusFft = false;
    private boolean statusMeshReady = false;
    private boolean statusAreaSAR = false;
    private boolean statusTranslate = false;
    private boolean gridFFT = false;
    private Vector vetorElementos;
    private int listGLMeshReady;
    private int listGLAreaSAR;
    private int listDisplay;
    private int listGrid;
    private Double range;
    private String fileName;
    private String legenda_eixoX,  legenda_eixoY;
    private Double maiorCampo;
    private Double menorCampo;
    private final static float ROTACAO_STEP = 1.0f;
    private final static float POSICAO_STEP = 0.5f;
    private final static float ZOOM_STEP = 0.5f;
    private float rotacaoX;
    private float rotacaoY;
    private float rotacaoZ;
    private float posicaoX;
    private float posicaoY;
    private float posicaoZ;

    public Renderizador() {
    }

    public void setVectorGraphFFT(Vector vAmp, Vector vTempo, float yMax, float yMin) {
        this.vAmp = vAmp;
        this.vTempo = vTempo;
        this.yMax = yMax;
        this.yMin = yMin;
        statusFft = true;

    }

    public void setQtdGrade(int gradeX, int gradeY) {
        this.qtdGradeX = gradeX;
        this.qtdGradeY = gradeY;
    }

    public float getQtdGradeX() {
        return qtdGradeX;
    }

    public float getQtdGradeY() {
        return qtdGradeY;
    }

    /**
     * 
     * @param valor
     */
    public void setRangeMaiorMenorCampo(Double valor, Double maior, Double menor) {
        range = valor;
        this.maiorCampo = maior;
        this.menorCampo = menor;
    }

    public void setVetorElementos(Vector list) {
        vetorElementos = list;
    }

    public void setStatusMeshReady(boolean status) {
        statusMeshReady = status;
    }

    public void setStatusAreaSAR(boolean status) {
        statusAreaSAR = status;
    }

    public void setLegendaEixoX(String legenda) {
        legenda_eixoX = legenda;
    }

    public void setLegendaEixoY(String legenda) {
        legenda_eixoY = legenda;
    }

    public void setPerspectiveGraph(float zPos, float xPos, float yPos) {

        //escala para caber na tela de acordo com a largura (passos de tempo)
        posicaoZ = zPos;
        posicaoX = xPos;
        posicaoY = yPos;
        rotacaoX = 0.0f;
        rotacaoY = 0.0f;
        rotacaoZ = 0.0f;

    }

    public void resetValues() {
        posicaoZ = -180.0f;
        posicaoY = -10.0f;
        posicaoX = -15.0f;
        rotacaoX = 36.0f;
        rotacaoY = 34.0f;
        rotacaoZ = 0.0f;
        glCanvas.display();
    }

    public void setGridFFT(boolean status) {
        gridFFT = status;
    }

    public boolean getGridFFT() {
        return gridFFT;
    }

    public void setPerspectiveMeshReady() {

        posicaoZ = -299.0f;
        posicaoY = 71.0f;
        posicaoX = 0.0f;
        rotacaoX = -40.0f;
        rotacaoY = -50.0f;
        rotacaoZ = -178.0f;

    }

    public void setPerspectiveAreaSAR() {

        posicaoX = -34.5f;
        posicaoY = -7.0f;
        posicaoZ = -40.0f;

        rotacaoX = -55.0f;
        rotacaoY = 0.0f;
        rotacaoZ = 9.0f;

    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public void setStatusSave(boolean status) {
        statusSave = status;
    }

    public void setGLCanvas(GLCanvas canvas) {
        glCanvas = canvas;
    }

    public void setStatusGrid(boolean statusGrid) {
        this.statusGrid = statusGrid;
    }

    public void setStatusTranslate(boolean statusTranslate) {
        this.statusTranslate = statusTranslate;
    }

    public GL getGL() {
        return gl;
    }

    /**
     * Rotaciona o eixo X em uma unidade positiva
     */
    public void addRotacaoX() {

        rotacaoX += ROTACAO_STEP;
        glCanvas.display();

    }

    /**
     * Rotaciona o eixo X em uma unidade negativa
     */
    public void subRotacaoX() {

        rotacaoX -= ROTACAO_STEP;
        glCanvas.display();

    }

    /**
     * Rotaciona o eixo Y em uma unidade positiva
     */
    public void addRotacaoY() {

        rotacaoY += ROTACAO_STEP;
        glCanvas.display();

    }

    /**
     * Rotaciona o eixo Y em uma unidade negativa
     */
    public void subRotacaoY() {

        rotacaoY -= ROTACAO_STEP;
        glCanvas.display();

    }

    /**
     * Rotaciona o eixo Z em uma unidade positiva
     */
    public void addRotacaoZ() {

        rotacaoZ += ROTACAO_STEP;
        glCanvas.display();

    }

    /**
     * Rotaciona o eixo Z em uma unidade negativa
     */
    public void subRotacaoZ() {

        rotacaoZ -= ROTACAO_STEP;
        glCanvas.display();

    }

    /**
     * Translada o eixo X em uma unidade positiva
     */
    public void addPosicaoX() {

        posicaoX += POSICAO_STEP;
        glCanvas.display();

    }

    /**
     * Translada o eixo X em uma unidade negativa
     */
    public void subPosicaoX() {

        posicaoX -= POSICAO_STEP;
        glCanvas.display();

    }

    /**
     * Translada o eixo Y em uma unidade positiva
     */
    public void addPosicaoY() {

        posicaoY += POSICAO_STEP;
        glCanvas.display();

    }

    /**
     * Translada o eixo Y em uma unidade negativa
     */
    public void subPosicaoY() {

        posicaoY -= POSICAO_STEP;
        glCanvas.display();

    }

    /**
     * Translada o eixo Z em uma unidade positiva
     */
    public void addPosicaoZ() {

        posicaoZ += ZOOM_STEP;
        glCanvas.display();

    }

    /**
     * Translada o eixo Z em uma unidade negativa
     */
    public void subPosicaoZ() {

        posicaoZ -= ZOOM_STEP;
        glCanvas.display();

    }

    public void moveRight() {
        posicaoY += 1.0f;
    }

    public void moveLeft() {
        posicaoY -= 1.0f;
    }

    public void moveUp() {
        posicaoX += 2.f;
    }

    public void moveDown() {
        posicaoX -= 2.f;
    }

    @Override
    public void display(GLAutoDrawable drawable) {
        gl = drawable.getGL();

        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();

        gl.glTranslatef(posicaoX, posicaoY, posicaoZ);

        gl.glRotatef(rotacaoX, 1.0f, 0.0f, 0.0f);
        gl.glRotatef(rotacaoY, 0.0f, 1.0f, 0.0f);
        gl.glRotatef(rotacaoZ, 0.0f, 0.0f, -1.0f);

        System.out.println("xP: " + posicaoX);
        System.out.println("yP: " + posicaoY);
        System.out.println("zP: " + posicaoZ);

        System.out.println("rotX: " + rotacaoX);
        System.out.println("rotY: " + rotacaoY);
        System.out.println("rotZ: " + rotacaoZ);


        if (statusGrid) {
            gl.glCallList(listGrid);//       // Habilita o modelo de coloriza��o de Gouraud
        }
        gl.glShadeModel(gl.GL_SMOOTH);
//
        // Define a reflet�ncia do material
        gl.glMaterialfv(gl.GL_FRONT, gl.GL_SPECULAR, especularidade, 0);
        // Define a concentra��o do brilho
        gl.glMateriali(gl.GL_FRONT, gl.GL_SHININESS, especMaterial);
        // Ativa o uso da luz ambiente
        gl.glLightModelfv(gl.GL_LIGHT_MODEL_AMBIENT, luzAmbiente, 0);

        // Define os par�metros da luz de n�mero 0
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, posicaoLuz, 0);
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, mat_shineness, 0);
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, luzEspecular, 0);
        gl.glLightfv(gl.GL_LIGHT0, gl.GL_AMBIENT, luzAmbiente, 0);
        gl.glLightfv(gl.GL_LIGHT0, gl.GL_DIFFUSE, luzDifusa, 0);

        // Habilita o depth-buffering
        gl.glEnable(GL.GL_DEPTH_TEST);
        //Habilita o uso de ilumina��o
        // gl.glEnable(GL.GL_LIGHTING);
        // Habilita a luz de n�mero 0
        //gl.glEnable(GL.GL_LIGHT0);
        // Habilita a defini��o da cor do material a partir da cor corrente
        //gl.glEnable(GL.GL_COLOR_MATERIAL);
        gl.glEnable(GL.GL_NORMALIZE);
        gl.glEnable(GL.GL_POLYGON_SMOOTH);

        gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
        //gl.glEnable(gl.GL_CULL_FACE);

//        if(print)
//            gl.glCallList(listDisplay);
//
//        //gl.glDeleteLists(0,1);

//        System.out.println("zPosition: " + zPosition);
//        System.out.println("yPosition: " + yPosition);
//        System.out.println("xPosition: " + xPosition);
//        System.out.println("rotateX: " + rotateX);
//        System.out.println("rotateY: " + rotateY);
//        System.out.println("rotateZ: " + rotateZ);



        if (statusFft) {

            renderResultAmpOnDisplay();
        }

        if (statusMeshReady) {
            gl.glCallList(listGLMeshReady);
        }
        if (statusAreaSAR) {
            gl.glCallList(listGLAreaSAR);
        }
        if (statusSave) {
            saveFrameAsPNG(drawable);
        }
    }

    void geraGrid() {

        //lista para o grid
        listGrid = gl.glGenLists(1);
        gl.glNewList(listGrid, gl.GL_COMPILE);
        gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE);
        gl.glBegin(GL.GL_QUADS);
        gl.glColor3f(1.0f, 1.0f, 1.0f);
        for (int x = -300; x < 300; x = x + 50) {
            for (int y = -300; y < 300; y = y + 50) {
                gl.glVertex2i(x, y);
                gl.glVertex2i(x + 50, y);
                gl.glVertex2i(x + 50, y + 50);
                gl.glVertex2i(x, y + 50);
            }
        }
        gl.glEnd();

        gl.glColor3f(0.0f, 0.0f, 0.0f);
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(0, 0, 0);
        gl.glVertex3f(5, 0, 0);
        gl.glEnd();
        gl.glRasterPos3f(4.5f, 0.5f, 0.5f);
        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_10, 'X');

        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(0, 0, 0);
        gl.glVertex3f(0, 5, 0);
        gl.glEnd();
        gl.glRasterPos3f(0.5f, 4.5f, 0.5f);
        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_10, 'Y');

        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(0, 0, 0);
        gl.glVertex3f(0, 0, 5);
        gl.glEnd();
        gl.glRasterPos3f(0.5f, 0.5f, 4.5f);
        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_10, 'Z');
        gl.glColor3f(1.0f, 1.0f, 1.0f);

        gl.glEndList();
    }

    void geraCubeElement() {
        //lista para imprimir os elementos na tela

        listDisplay = gl.glGenLists(1);
        gl.glNewList(listDisplay, gl.GL_COMPILE);
//        System.out.println("Tamanho da lista(Vector): " + list.length);
        //gl.glColor3f(0.2f, 1.0f, 0.2f);
        //imprimindo n espa�os de tempo


        for (int i = 0; i < list.length; i++) {
            gl.glPushMatrix();
            //gl.glEnable(gl.GL_BLEND);
            c = (CubeElement) list[i];
//               if ( c.getCor() > 0.182  )
            gl.glColor3d(c.getCor(), 0.0, 0.3);

            gl.glTranslated(c.getX(), c.getY(), c.getZ());

            glut.glutSolidCube(0.2f);
            gl.glPopMatrix();
            gl.glFlush();
        }



//           gl.glPointSize(8.0f);
//           gl.glBegin(gl.GL_POINTS);
//               for(int i= 0; i < list.size(); i++) {
//                    c = (CubeElement)list.get(i);
////                 if ( c.getCor() > 0.066  )
//                   gl.glColor3d(c.getCor(), 0.2, 0.0);
//
////               if ( (c.getCor() > 0.033) && (c.getCor() < 0.066)  )
////                   gl.glColor3d(0.0, c.getCor(), 0.0);
////
////               if ( (c.getCor() > 0.00) && (c.getCor() < 0.033)  )
////                   gl.glColor3d(0.0, 0.0, c.getCor());
//
//                   gl.glVertex3f(c.getX(), c.getY(), c.getZ());
//
//               }
//
//           gl.glEnd();

        gl.glEndList();


    }

    void meshReady() {
        listGLMeshReady = gl.glGenLists(1);
        gl.glNewList(listGLMeshReady, gl.GL_COMPILE_AND_EXECUTE);

        gl.glPointSize(8.0f);
        gl.glBegin(gl.GL_POINTS);

        for (int i = 0; i < vetorElementos.size(); i++) {

            c = (CubeElement) vetorElementos.get(i);
            // System.out.println("cor: " + c.getCor());

            if ((c.getCor() > 0.0) && (c.getCor() < 0.2)) {
                gl.glColor3d(0.2, 0.2, c.getCor());
            }
            if ((c.getCor() > 0.2) && (c.getCor() < 0.4)) {
                gl.glColor3d(0.1, c.getCor(), 0.1);
            }
            if ((c.getCor() > 0.4) && (c.getCor() < 0.6)) {
                gl.glColor3d(0.5, c.getCor(), 0.1);
            }
            if ((c.getCor() > 0.6) && (c.getCor() < 0.65)) {
                gl.glColor3d(0.15, c.getCor(), 0.3);
            }
            if ((c.getCor() > 0.65) && (c.getCor() < 0.7)) {
                gl.glColor3d(0.2, c.getCor(), 0.4);
            }
            if ((c.getCor() > 0.7) && (c.getCor() < 0.75)) {
                gl.glColor3d(0.6, c.getCor(), 0.9);
            }
            if ((c.getCor() > 0.8)) {
                gl.glColor3d(c.getCor(), 0.8, 0.8);
            }
            gl.glVertex3d(c.getX() - 50, c.getY() - 50, c.getCor() - 50);

        }

        gl.glEnd();


        gl.glEndList();

    }

    void geraAreaSAR() {

//        System.out.println("geraAreaSAr");

        listGLAreaSAR = gl.glGenLists(1);
        gl.glNewList(listGLAreaSAR, gl.GL_COMPILE_AND_EXECUTE);

        Double intervalo = range / 4;

        for (int i = 0; i < vetorElementos.size(); i++) {

            c = (CubeElement) vetorElementos.get(i);

            /* Recebe range da cor vermelha */
            if ((c.getCor() <= maiorCampo) && (c.getCor() >= (maiorCampo - intervalo))) {
                Double cor = (c.getCor() - menorCampo) / (range / 1000);
                gl.glColor4d(cor / 200, 0.0, 0.0, 1.0);

            }
            /* Recebe range da cor amarela */
            if ((c.getCor() < (maiorCampo - intervalo)) && (c.getCor() >= (maiorCampo - (2 * intervalo)))) {
                Double cor = (c.getCor() - menorCampo) / (range / 1000);
                gl.glColor4d(cor / 200, cor / 200, 0.0, 1.0);
            }
            /* Recebe range da cor verde */
            if ((c.getCor() < (maiorCampo - (2 * intervalo))) && (c.getCor() >= (maiorCampo - (3 * intervalo)))) {
                Double cor = (c.getCor() - menorCampo) / (range / 1000);
                gl.glColor4d(0.0, cor / 200, 0.0, 1.0);
            }
            /* Recebe range da cor azul */
            if ((c.getCor() < (maiorCampo - (3 * intervalo))) && (c.getCor() >= menorCampo)) {
                Double cor = (c.getCor() - menorCampo) / (range / 1000);
                gl.glColor4d(0.0, 0.0, cor / 200, 1.0);
            }

            Double cor = (c.getCor() - menorCampo) / (range / 1000);
//            System.out.println("cor: " + c.getCor()/100 );
//            System.out.println("x: " + c.getX());
//            System.out.println("y: " + c.getY());
//            System.out.println("z: " + c.getZ());


            gl.glBegin(gl.GL_QUADS);	// Face frontal
            gl.glNormal3f(0f, 0f, 1f);  // Normal da face
            gl.glVertex3d(c.getX() - 0.5f, c.getY() + 0.5f, (cor / 100) + 0.2f);
            gl.glVertex3d(c.getX() + 0.5f, c.getY() + 0.5f, (cor / 100) + 0.2f);
            gl.glVertex3d(c.getX() + 0.5f, c.getY() - 0.5f, (cor / 100) + 0.2f);
            gl.glVertex3d(c.getX() - 0.5f, c.getY() - 0.5f, (cor / 100) + 0.2f);
            gl.glEnd();

            gl.glBegin(gl.GL_QUADS);	// Face lateral direita
            gl.glNormal3d(0f, 0f, -1f); // Normal da face
            gl.glVertex3d(c.getX() + 0.5f, c.getY() + 0.5f, (cor / 100) + 0.2f);
            gl.glVertex3d(c.getX() + 0.5f, c.getY() + 0.5f, (cor / 100) - 0.2f);
            gl.glVertex3d(c.getX() + 0.5f, c.getY() - 0.5f, (cor / 100) - 0.2f);
            gl.glVertex3d(c.getX() + 0.5f, c.getY() - 0.5f, (cor / 100) + 0.2f);
            gl.glEnd();

            gl.glBegin(gl.GL_QUADS);	// Face de cima
            gl.glNormal3f(-1f, 0f, 0f); // Normal da face
            gl.glVertex3d(c.getX() - 0.5f, c.getY() + 0.5f, (cor / 100) + 0.2f);
            gl.glVertex3d(c.getX() - 0.5f, c.getY() + 0.5f, (cor / 100) - 0.2f);
            gl.glVertex3d(c.getX() + 0.5f, c.getY() + 0.5f, (cor / 100) - 0.2f);
            gl.glVertex3d(c.getX() + 0.5f, c.getY() + 0.5f, (cor / 100) + 0.2f);
            gl.glEnd();

            gl.glBegin(gl.GL_QUADS);	// Face lateral esquerda
            gl.glNormal3f(1f, 0f, 0f);  // Normal da face
            gl.glVertex3d(c.getX() - 0.5f, c.getY() + 0.5f, (cor / 100) + 0.2f);
            gl.glVertex3d(c.getX() - 0.5f, c.getY() + 0.5f, (cor / 100) - 0.2f);
            gl.glVertex3d(c.getX() - 0.5f, c.getY() - 0.5f, (cor / 100) - 0.2f);
            gl.glVertex3d(c.getX() - 0.5f, c.getY() - 0.5f, (cor / 100) + 0.2f);
            gl.glEnd();

            gl.glBegin(gl.GL_QUADS);	// Face trazeira
            gl.glNormal3f(0f, 1f, 0f);  // Normal da face
            gl.glVertex3d(c.getX() - 0.5f, c.getY() + 0.5f, (cor / 100) - 0.2f);
            gl.glVertex3d(c.getX() + 0.5f, c.getY() + 0.5f, (cor / 100) - 0.2f);
            gl.glVertex3d(c.getX() + 0.5f, c.getY() - 0.5f, (cor / 100) - 0.2f);
            gl.glVertex3d(c.getX() - 0.5f, c.getY() - 0.5f, (cor / 100) - 0.2f);
            gl.glEnd();

            gl.glBegin(gl.GL_QUADS);	// Face de baixo
            gl.glNormal3f(0f, -1f, 0f); // Normal da face
            gl.glVertex3d(c.getX() - 0.5f, c.getY() - 0.5f, (cor / 100) + 0.2f);
            gl.glVertex3d(c.getX() - 0.5f, c.getY() - 0.5f, (cor / 100) - 0.2f);
            gl.glVertex3d(c.getX() + 0.5f, c.getY() - 0.5f, (cor / 100) - 0.2f);
            gl.glVertex3d(c.getX() + 0.5f, c.getY() - 0.5f, (cor / 100) + 0.2f);
            gl.glEnd();
        }

        gl.glEndList();

    }

    void renderResultAmpOnDisplay() {
        /* recebe 2 vetores de entrada, eixo do Tempo e eixo de Amplitude
         * e cria grafico 2D com legenda         */

/////////////  Desenho das Bordas do Gr�fico 2D ///////////////////////////////

        this.setPerspectiveGraph(-75, -53, -24);
        //cor das bordas do grafico
        gl.glColor3f(0.0f, 0.0f, 0.0f); //preta
        gl.glLineWidth(1.0f);           //espessura

        //eixo Y esquerdo
        gl.glBegin(gl.GL_LINES);
        gl.glVertex2d(0, 0);
        gl.glVertex2d(0, 56);
        gl.glEnd();

        //desenhando eixo Y direito
        gl.glBegin(gl.GL_LINES);
        gl.glVertex2d(100, 56);
        gl.glVertex2d(100, 0);
        gl.glEnd();

        // eixo X inferior
        gl.glBegin(gl.GL_LINES);
        gl.glVertex2d(0, 0);
        gl.glVertex2d(100, 0);
        gl.glEnd();

        // eixo X superior
        gl.glBegin(gl.GL_LINES);
        gl.glVertex2d(0, 56);
        gl.glVertex2d(100, 56);
        gl.glEnd();


///////////////////////////////////////////////////////////////////////////////

////////////// DEFININDO ESCALA A PATIR DO VETOR TEMPO (X) ////////////////////

        //dados dos vetores X(tempo) e Y(Amplitude)

        float tamBlocoX, tamBlocoY;           //qtd de unidades de cada eixo
        float pontosXGL, pontosYGL;         //pontos dos eixos na visao do OpenGL (legenda)
        float pontosValorX, pontosValorY;   //pontos dos eixos (legenda) na visao dos vetores lidos

        float x = 0; //traco no eixo x come�a em zero
        int valorY = 0;
        float step = 1;

        xMax = vTempo.size();
        tamBlocoX = 100; //assim, ficam 100 unidades para parametrizar o vTempo
        tamBlocoY = 56; // por enquanto � fixo ...
        pontosXGL = tamBlocoX / qtdGradeX;    // 7 foi escolhido baseado no grafico do Matlab
        pontosYGL = tamBlocoY / qtdGradeY;    // 8 foi escolhido baseado no grafico do Matlab
        pontosValorX = xMax / qtdGradeX;
        pontosValorY = yMax / qtdGradeY;

        //parametros para tra�o tracejado no eixo X
        gl.glEnable(gl.GL_LINE_STIPPLE);
        gl.glLineStipple(1, (short) 0xf0f0);

        // tra�os para o Eixo X somente se xMax for maior que 100

        float valorXinicial = 0;
        if (xMax > 100) {

            step = (int) (xMax / 100) + 1;
            tamBlocoX = xMax / step;
            pontosXGL = tamBlocoX / qtdGradeX;
            pontosValorX = xMax / qtdGradeX;

            for (int i = 0; i <= qtdGradeX; i++) {

                // pequeno 'tra�o' que separa cada valor do eixo X
                if (gridFFT) {    //caso grid esteja 'on'
                    gl.glEnable(gl.GL_LINE_STIPPLE);
                    gl.glBegin(gl.GL_LINES);
                    gl.glVertex2f(x, 0.0f);
                    gl.glVertex2f(x, 56.0f);
                    gl.glEnd();
                } else {
                    // pequeno 'tra�o' que separa cada valor do eixo X
                    gl.glDisable(gl.GL_LINE_STIPPLE);
                    gl.glBegin(gl.GL_LINES);
                    gl.glVertex2f(x, 0.0f);
                    gl.glVertex2f(x, 1.5f);
                    gl.glEnd();

                }

                //desenhando numeros em cada valor do eixo X
                gl.glPushMatrix();
                gl.glRotatef(0, 0, 0, 1);
                gl.glTranslatef(x, -5.0f, 0.0f);
                gl.glScaled(0.013, 0.013, 0.013);
                gl.glDisable(gl.GL_LINE_STIPPLE);   //desabilitando tracejado de linhas
                glut.glutStrokeString(glut.STROKE_ROMAN, String.valueOf((int) valorXinicial));
                x += pontosXGL;
                valorXinicial += pontosValorX;
                gl.glPopMatrix();

            }

            // tra�os para o Eixo Y
            float y = 0; //traco no eixo y come�a em zero
            float valorYinicial = yMin;
            pontosValorY = (yMax - yMin) / qtdGradeY;
            String numero;
            for (int i = 0; i <= qtdGradeY; i++) {

                // pequeno 'tra�o' que separa cada valor do eixo Y
                if (gridFFT) {    //caso grid esteja 'on'
                    gl.glEnable(gl.GL_LINE_STIPPLE);
                    gl.glBegin(gl.GL_LINES);
                    gl.glVertex2f(0.0f, y);
                    gl.glVertex2f(100.0f, y);
                    gl.glEnd();
                } else {
                    // pequeno 'tra�o' que separa cada valor do eixo Y
                    gl.glDisable(gl.GL_LINE_STIPPLE);
                    gl.glBegin(gl.GL_LINES);
                    gl.glVertex2f(0.0f, y);
                    gl.glVertex2f(1.5f, y);
                    gl.glEnd();

                }


                //    desenhando numeros em cada valor do eixo Y
                gl.glPushMatrix();
                gl.glRotatef(0, 0, 0, 1);
                gl.glTranslatef(-13.0f, y, 0.0f);
                gl.glScaled(0.013, 0.013, 0.013);
                gl.glDisable(gl.GL_LINE_STIPPLE);   //desabilitando tracejado de linhas
                glut.glutStrokeString(glut.STROKE_ROMAN, String.valueOf(Float.valueOf(valorYinicial)));
                y += pontosYGL;
                valorYinicial += pontosValorY;
                gl.glPopMatrix();



            }
        } else {

            x = 0;
            int step2 = (int) (xMax / qtdGradeX);

            for (int i = 0; i <= qtdGradeX; i++) {

                if (gridFFT) {    //caso grid esteja 'on'
                    gl.glEnable(gl.GL_LINE_STIPPLE);
                    gl.glBegin(gl.GL_LINES);
                    gl.glVertex2f(x, 0.0f);
                    gl.glVertex2f(x, 56.0f);
                    gl.glEnd();
                } else {
                    // pequeno 'tra�o' que separa cada valor do eixo X
                    gl.glDisable(gl.GL_LINE_STIPPLE);
                    gl.glBegin(gl.GL_LINES);
                    gl.glVertex2f(x, 0.0f);
                    gl.glVertex2f(x, 1.5f);
                    gl.glEnd();

                }

                //desenhando numeros em cada valor do eixo X
                gl.glPushMatrix();
                gl.glRotatef(0, 0, 0, 1);
                gl.glTranslatef(x, -5.0f, 0.0f);
                gl.glScaled(0.013, 0.013, 0.013);
                gl.glDisable(gl.GL_LINE_STIPPLE);   //desabilitando tracejado de linhas
                glut.glutStrokeString(glut.STROKE_ROMAN, String.valueOf(x));
                x += step2;
                gl.glPopMatrix();

            }
            // tra�os para eixo Y

            float y = 0; //traco no eixo y come�a em zero
            float valorYinicial = yMin;
            pontosValorY = (yMax - yMin) / qtdGradeY;

            for (int i = 0; i <= qtdGradeY; i++) {

                // pequeno 'tra�o' que separa cada valor do eixo Y
                if (gridFFT) {    //caso grid esteja 'on'
                    gl.glEnable(gl.GL_LINE_STIPPLE);
                    gl.glBegin(gl.GL_LINES);
                    gl.glVertex2f(0.0f, y);
                    gl.glVertex2f(100.0f, y);
                    gl.glEnd();
                } else {
                    // pequeno 'tra�o' que separa cada valor do eixo Y
                    gl.glDisable(gl.GL_LINE_STIPPLE);
                    gl.glBegin(gl.GL_LINES);
                    gl.glVertex2f(0.0f, y);
                    gl.glVertex2f(1.5f, y);
                    gl.glEnd();

                }

                //    desenhando numeros em cada valor do eixo Y
                gl.glPushMatrix();
                gl.glRotatef(0, 0, 0, 1);
                gl.glTranslatef(-13.0f, y, 0.0f);
                //gl.glTranslatef(-13.0f, y-0.8f, 0.0f);
                gl.glScaled(0.013, 0.013, 0.013);
                gl.glDisable(gl.GL_LINE_STIPPLE);   //desabilitando tracejado de linhas
                glut.glutStrokeString(glut.STROKE_ROMAN, String.valueOf(Float.valueOf(valorYinicial)));
                y += pontosYGL;
                valorYinicial += pontosValorY;
                gl.glPopMatrix();

            }
        }

        gl.glDisable(gl.GL_LINE_STIPPLE); //desabilitando tracejado

        //Escrevendo 'Amplitude' e 'Passos de Tempo como Legenda
        gl.glPushMatrix();
        gl.glRotatef(0, 0, 0, 1);
        gl.glTranslatef(30.0f, -10.0f, -0.0f);
        gl.glScaled(0.025, 0.025, 0.025);
        /* Eixo X - Legenda */
        glut.glutStrokeString(glut.STROKE_ROMAN, legenda_eixoX);
        gl.glPopMatrix();

        gl.glPushMatrix();
        gl.glRotatef(90, 0, 0, 1);
        gl.glTranslatef(20.0f, 0.0f, 20.0f);
        gl.glScaled(0.025, 0.025, 0.025);
        /* Eixo Y - Legenda */
        glut.glutStrokeString(glut.STROKE_ROMAN, legenda_eixoY);
        gl.glPopMatrix();


        //plotando Y em rela��o a X
        gl.glColor3f(0.0f, 0.0f, 1.0f);     //azul
        gl.glLineWidth(1.0f);               //espessura

        x = 0;
        valorY = 0;
        pontosXGL = xMax;
        float yMaxGL = 56;

        float yMaxAbs, yValor, yValorAbs, yGL;
        yMaxAbs = yMax - yMin;
        int cont = 0;
        int cont2 = 0;
        //float stepXGL = tamBlocoX / 100;

        if (xMax > 100) {                 //se ultrapassar o limite de unidades do eixo X

            step = (int) ((xMax / 100) + 1);
            pontosXGL = 100;

            // Plotando pontos na tela normalizados em 100 unidades

            gl.glBegin(gl.GL_LINE_STRIP);
            while (x <= pontosXGL) {

                while (valorY < xMax) {

                    yValor = (Float) vAmp.get(valorY);
                    yValorAbs = yValor - yMin;
                    yGL = (yValorAbs * 56) / yMaxAbs;
                    gl.glVertex2f(x, yGL);
                    x++;
                    valorY += step;
                    cont++;
                }
                x++;

                cont2++;
            }

            gl.glEnd();

        } else {

            gl.glBegin(gl.GL_LINE_STRIP);
            for (int i = 0; i < xMax; i++) {

                yValor = (Float) vAmp.get(i);
                yValorAbs = yValor - yMin;
                yGL = (yValorAbs * 56) / yMaxAbs;
                gl.glVertex2f(i, yGL);

            }
            gl.glEnd();

        }


    }

    public void displayChanged(GLAutoDrawable gLDrawable, boolean modeChanged, boolean deviceChanged) {
    }

    public void init(GLAutoDrawable drawable) {
        // Obtem referência ao GL
        gl = drawable.getGL();
        // Especifica Cor de Fundo
        gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        // Pinta o Fundo da Tela com a Cor Escolhida
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        // Habilita a definição da cor do material a partir da cor corrente
        gl.glEnable(GL.GL_COLOR_MATERIAL);
        // Habilita o depth-buffer
        gl.glEnable(GL.GL_DEPTH_TEST);
        // Habilita o modelo de colorização de Gouraud
        gl.glShadeModel(gl.GL_SMOOTH);

        // Transparência
        gl.glEnable(gl.GL_BLEND);
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA);

        // Estabelece os parâmetros do modelo de iluminação ambiente
        gl.glLightModelfv(gl.GL_LIGHT_MODEL_AMBIENT, luzAmbiente, 0);
        //Habilita uso de iluminação
        gl.glEnable(GL.GL_LIGHTING);
        // Habilita luz de número 0
        gl.glEnable(GL.GL_LIGHT0);

        drawable.addKeyListener(this);
        drawable.addMouseListener(this);

        geraGrid();


        if (statusMeshReady) {
            meshReady();
        }
        if (statusAreaSAR) {
            geraAreaSAR();
        }
    }

    public void reshape(GLAutoDrawable gLDrawable, int x, int y, int width, int height) {

        double xx, yy, ww, hh;
        gl = gLDrawable.getGL();
        if (height <= 0) {
            height = 1;
        }
        final float h = (float) width / (float) height;
        gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(60.0f, h, 1.5, 1000.0);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    private ByteBuffer getFrameData(GL gl, ByteBuffer pixelsRGB) {

        // Read Frame back into our ByteBuffer.
        gl.glReadBuffer(GL.GL_BACK);
        gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
        gl.glReadPixels(0, 0, glCanvas.getWidth(), glCanvas.getHeight(),
                GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
                pixelsRGB);

        return pixelsRGB;
    }

    private BufferedImage copyFrame(GL gl) {

        // Create a ByteBuffer to hold the frame data.
        java.nio.ByteBuffer pixelsRGB =
                //BufferUtils.createByteBuffer
                ByteBuffer.allocateDirect(glCanvas.getWidth() * glCanvas.getHeight() * 3);

        // Get date from frame as ByteBuffer.
        getFrameData(gl, pixelsRGB);

        return transformPixelsRGBBuffer2ARGB_ByHand(pixelsRGB);
    }

    private BufferedImage transformPixelsRGBBuffer2ARGB_ByHand(ByteBuffer pixelsRGB) {
        // Transform the ByteBuffer and get it as pixeldata.

        int[] pixelInts = new int[glCanvas.getWidth() * glCanvas.getHeight()];

        // Convert RGB bytes to ARGB ints with no transparency.
        // Flip image vertically by reading the
        // rows of pixels in the byte buffer in reverse
        // - (0,0) is at bottom left in OpenGL.
        //
        // Points to first byte (red) in each row.
        int p = glCanvas.getWidth() * glCanvas.getHeight() * 3;
        int q; // Index into ByteBuffer
        int i = 0; // Index into target int[]
        int w3 = glCanvas.getWidth() * 3; // Number of bytes in each row
        for (int row = 0; row < glCanvas.getHeight(); row++) {
            p -= w3;
            q = p;
            for (int col = 0; col < glCanvas.getWidth(); col++) {
                int iR = pixelsRGB.get(q++);
                int iG = pixelsRGB.get(q++);
                int iB = pixelsRGB.get(q++);
                pixelInts[i++] =
                        0xFF000000 | ((iR & 0x000000FF) << 16) |
                        ((iG & 0x000000FF) << 8) | (iB & 0x000000FF);
            }
        }

        // Create a new BufferedImage from the pixeldata.
        BufferedImage bufferedImage =
                new BufferedImage(glCanvas.getWidth(), glCanvas.getHeight(),
                BufferedImage.TYPE_INT_ARGB);
        bufferedImage.setRGB(0, 0, glCanvas.getWidth(), glCanvas.getHeight(),
                pixelInts, 0, glCanvas.getWidth());

        return bufferedImage;
    }

    public void saveFrameAsPNG(GLAutoDrawable gLDrawable) {

        gl = gLDrawable.getGL();
        // Open File

        File outputFile = new File(fileName);

        // Write file.
        try {
            javax.imageio.ImageIO.write(copyFrame(gl), "PNG", outputFile);

        } catch (IOException e) {
            System.out.println("Error: ImageIO.write.");
            e.printStackTrace();
        }
    }

    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
            System.exit(0);
        } else {
            switch (e.getKeyChar()) {
                case 'x':
                    addRotacaoX();
                    break;
                case 'X':
                    subRotacaoX();
                    break;
                case 'y':
                    addRotacaoY();
                    break;
                case 'Y':
                    subRotacaoY();
                    break;
                case 'z':
                    addRotacaoZ();
                    break;
                case 'Z':
                    subRotacaoZ();
                    break;
                case '+':
                    addPosicaoZ();
                    break;
                case '-':
                    subPosicaoZ();
                    break;
                case 'w':
                    addPosicaoY();
                    break;
                case 'W':
                    addPosicaoY();
                    break;
                case 's':
                    subPosicaoY();
                    break;
                case 'S':
                    subPosicaoY();
                    break;
                case 'd':
                    addPosicaoX();
                    break;
                case 'D':
                    addPosicaoX();
                    break;
                case 'a':
                    subPosicaoX();
                    break;
                case 'A':
                    subPosicaoX();
                    break;

                case 'r':
                    resetValues();
                    break;
                case 'R':
                    resetValues();
                    break;
            }
        }
    }

// no use for the following events (of KeyListener)
    public void keyReleased(KeyEvent e) {
    }

    public void keyTyped(KeyEvent e) {
    }
// comes with MouseListener, invoked if user hits a mouse button
    public void mousePressed(MouseEvent me) {
    }
// no use for the following events (of MouseListener)
    public void mouseClicked(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent arg0) {
    }

    public void mouseEntered(MouseEvent arg0) {
    }

    public void mouseExited(MouseEvent arg0) {
    }

    public void mouseDragged(MouseEvent e) {
    }

    public void mouseMoved(MouseEvent e) {
    }

    @Override
    public void mouseWheelMoved(MouseWheelEvent e) {

        if (e.getWheelRotation() == -1) {
            addPosicaoZ();
            glCanvas.display();

        } else {
            subPosicaoZ();
            glCanvas.display();
        }
    }
}


